
public class Location {

	private double latitude;
	
	private double longitude;
	
	private double altitude;
	
	public Location(double lat, double lon, double alt){
		
		this.latitude = lat;
		this.longitude = lon;
		this.altitude = alt;
		
	}
	
	public void setAltitude(double alt){
		
		this.altitude = alt;
	}
	
	public double getAltitude(){
		
		return this.altitude;
	}

	public double getLatitude(){
		
		return this.latitude;
	}
	
	public double getLongitude(){
		
		return this.longitude;
	}
	
	public double getLatitudeRad(){
		
		return this.latitude*(Math.PI/180);
	}
	
	public double getLongitudeRad(){
		
		return this.longitude*(Math.PI/180);
	}
	
	public double getBearing(Location loc){
		
		double deltaLon = loc.getLongitude()-this.longitude;
		
		double y = Math.sin(deltaLon) * Math.cos(loc.getLatitude());
        double x = Math.cos(this.latitude)*Math.sin(loc.getLatitude()) -
                Math.sin(this.latitude)*Math.cos(loc.getLatitude())*Math.cos(deltaLon);
        return Math.toDegrees(Math.atan2(y, x));
		
	}
	
	public double getDistance(Location loc){
		
		double R = 6371; // raio da terra em km
		double dLat = Math.toRadians(loc.getLatitude()-this.latitude);
		double dLon = Math.toRadians(loc.getLongitude()-this.longitude);
		double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
		        Math.cos(this.getLatitudeRad()) * Math.cos(loc.getLatitudeRad()) * 
		        Math.sin(dLon/2) * Math.sin(dLon/2); 
		double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
		return R * c;
		
	}
	
	
	// Movimento
	public void move(double distft, double direction){
        double distNM=distft/(185200.0/30.48); //convert to nm (does that stand for nautical miles??)
        
        double dirRAD=direction*Math.PI/180; // radians
        
        // spherical code
        distNM /=(180*60/Math.PI);  // in radians
        direct(this.getLatitudeRad(),-this.getLongitudeRad(),dirRAD,distNM); //EAST is negative for these calcs, not West as is normally accepted.
    }
	
	private void direct(double latRad, double lonRad, double dirRad, double distNM){
        double EPS= 0.00000000005;
        double dlon,lat,lon;
        /*if ((Math.abs(Math.cos(latRad))<EPS) && !(Math.abs(Math.sin(dirRad))<EPS)){
            throw new Exception("Only N-S courses are meaningful, starting at a pole!");
        }*/
        
        lat=Math.asin(Math.sin(latRad)*Math.cos(distNM)+Math.cos(latRad)*Math.sin(distNM)*Math.cos(dirRad));
        if (Math.abs(Math.cos(lat))<EPS){
            lon=0; //endpoint a pole
        }else{
            dlon=Math.atan2(Math.sin(dirRad)*Math.sin(distNM)*Math.cos(latRad), Math.cos(distNM)-Math.sin(latRad)*Math.sin(lat));
            lon=mod( lonRad-dlon+Math.PI,2*Math.PI )-Math.PI;
        }
        
        this.latitude=lat*(180/Math.PI);
        //TODO meti menos aki mas n sei se deve ficar
        this.longitude=-lon*(180/Math.PI);
    }
	
	private double mod(double x, double y){
        return x-y*Math.floor(x/y);
    }
	
}
